/*
7-2 公路村村通（30 分）
	现有村落间道路的统计数据表中，列出了有可能建设成标准公路的若干条道路的成本，求使每个村落都有公路连通所需要的最低成本。

	输入格式:
	输入数据包括城镇数目正整数N（≤1000）和候选道路数目M（≤3N）；随后的M行对应M条道路，每行给出3个正整数，分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见，城镇从1到N编号。

	输出格式:
	输出村村通需要的最低成本。如果输入数据不足以保证畅通，则输出−1，表示需要建设更多公路。

	输入样例:
	6 15
	1 2 5
	1 3 3
	1 4 7
	1 5 4
	1 6 2
	2 3 4
	2 4 6
	2 5 2
	2 6 6
	3 4 6
	3 5 1
	3 6 1
	4 5 10
	4 6 8
	5 6 3
	输出样例:
	12
*/



#include <iostream>
#include <stack>
#define INFINITE 100000
using namespace std;
class Dist
{
public:
	int index;
	int length;
	int pre;
	Dist()
	{
		index = 0;
		length = 0;
		pre = 0;
	}
};
class Edge
{
public:
	int from, to, weight;   //程序中城镇从0开始编号,from，to是城镇的编号
	Edge()
	{
		from = -1;
		to = -1;
		weight = 0;
	}
	Edge(int f, int t, int w)
	{
		from = f;
		to = t;
		weight = w;
	}
};
class Data
{
public:
	int iD;
	int weight;
	Data()
	{
		iD = -1;
		weight = 0;
	}
};
class Node
{
public:
	Data info;
	Node*next;
	Node()
	{
		next = nullptr;
	}
	Node(int id, int w)
	{
		info.iD = id;
		info.weight = w;
		next = nullptr;
	}
};
class Graph
{
	int numVertex;  //顶点的个数
	int numEdge;    //边的个数
	bool *mark;     //标记数组
	int *inDegree;  //各顶点的入度
	Node *graList;  //存储顶点
public:
	Graph(int numVer)
	{
		numVertex = numVer;
		numEdge = 0;
		mark = new bool[numVertex];
		inDegree = new int[numVertex];
		graList = new Node[numVertex];
		for (int i = 0; i < numVertex; i++)
		{
			mark[i] = false;   //所有的标记设置为false
			inDegree[i] = 0;   //所有的入度设置为 0
			graList[i].info.iD = i;   //节点的编号为i
		}
	}
	void setEdge(int f, int t, int w)
	{
		Node *pointer = &graList[f];
		while (pointer->next != nullptr && (pointer->next)->info.iD < t)
			pointer = pointer->next;
		if (pointer->next == nullptr)
		{
			pointer->next = new Node(t, w);
			numEdge++;
			inDegree[t]++;
		}
		else if (pointer->next->info.iD == t)
			pointer->next->info.weight == w;
		else
		{
			Node *temp = pointer->next;
			pointer->next = new Node(t, w);
			pointer->next->next = temp;
			numEdge++;
			inDegree[t]++;
		}
	}
	Edge firstEdge(int oneVer)  //传入的是城镇的编号
	{
		Edge myEdge;
		myEdge.from = oneVer;
		Node*temp = &graList[oneVer];
		if (temp->next != nullptr)
		{
			myEdge.to = temp->next->info.iD;
			myEdge.weight = temp->next->info.weight;
		}
		return myEdge;
	}
	Edge nextEdge(Edge e)  //e中的from、to是城镇的编号
	{
		Edge myEdge;
		myEdge.from = e.from;
		Node *pointer = &graList[e.from];
		while (pointer->next != nullptr&&pointer->next->info.iD <= e.to)
			pointer = pointer->next;
		if (pointer->next != nullptr)
		{
			myEdge.to = pointer->next->info.iD;
			myEdge.weight = pointer->next->info.weight;
		}
		return myEdge;
	}
	bool isEdge(Edge e)
	{
		if (e.from == -1 || e.to == -1 || e.weight == 0)
			return false;
		return true;
	}
	void creatGraph(Edge*data, int numEdge)
	{
		for (int i = 0; i < numEdge; i++)
		{
			setEdge(data[i].from, data[i].to, data[i].weight);
			setEdge(data[i].to, data[i].from, data[i].weight);
		}
	}
	void testCreatGraph()
	{
		for (int i = 0; i < numVertex; i++)
		{
			Node *temp = &graList[i];
			while (temp != NULL)
			{
				cout << temp->info.iD << " ";
				temp = temp->next;
			}
			cout << endl;
		}
	}
	void DFS(int v)  //传入题上城镇的编号，从1开始的那种
	{
		v--;
		mark[v] = true;
		cout << graList[v].info.iD << " ";
		for (Edge e = firstEdge(v); isEdge(e); e = nextEdge(e))
		{
			if (mark[e.to] != true)
				DFS(e.to + 1);
		}
	}
	void leastCostWithPrim()
	{
		//默认起点是0
		stack<Edge>edgeStack;
		Dist *dist = new Dist[numVertex];
		for (int i = 0; i < numVertex; i++)
		{
			mark[i] = false;
			dist[i].index = i;
			dist[i].length = INFINITE;
			dist[i].pre = 0;
		}
		dist[0].length = 0;
		mark[0] = true;
		int v = 0;
		for (int i = 0; i < numVertex - 1; i++)
		{
			if (dist[v].length == INFINITE)
			{
				cout << "-1" << endl;
				return;
			}
			for (Edge e = firstEdge(v); isEdge(e); e = nextEdge(e))
				if (mark[e.to] == false && dist[e.to].length > e.weight)
				{
					dist[e.to].length = e.weight;
					dist[e.to].pre = v;
				}
			for (int i = 0; i<numVertex; i++)
				if (mark[i] == false)
				{
					v = i;
					break;
				}
			for (int i = 0; i < numVertex; i++)
			{
				if (mark[i] == false && (dist[i].length < dist[v].length))
					v = i;
			}
			mark[v] = true;
			edgeStack.push(Edge(dist[v].pre, dist[v].index, dist[v].length));
		}
		int cost = 0;
		for (int i = 0; i < numVertex - 1; i++)
		{
			if (!edgeStack.empty())
			{
				cost = cost + edgeStack.top().weight;
				edgeStack.pop();
			}
		}
		cout << cost << endl;
	}
	~Graph()
	{
		delete[]mark;
		delete[]inDegree;
		for (int i = 0; i < numVertex; i++)
		{
			Node *pointer = graList[i].next;
			while (pointer != nullptr)
			{
				Node *temp = pointer;
				pointer = pointer->next;
				delete temp;
			}
		}
	}
};
int main()
{
	int numVer;
	cin >> numVer;
	Graph g(numVer);
	int numEdge;
	cin >> numEdge;
	Edge *dataEdge = new Edge[numEdge];
	for (int i = 0; i < numEdge; i++)
	{
		cin >> dataEdge[i].from >> dataEdge[i].to >> dataEdge[i].weight;
		dataEdge[i].from--;
		dataEdge[i].to--;
	}
	g.creatGraph(dataEdge, numEdge);
//	g.testCreatGraph();
//	g.DFS(3);
	g.leastCostWithPrim();
	return 0;
}